﻿using Blm.Utils.Extensions;
using Language.Resource;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Pipelines.Sockets.Unofficial.Arenas;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.Data;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Utility;

namespace VisionCloud.Service.Ms
{
    public class StandardService
    {
        public IUnitOfWork UnitOfWork { get; set; }
        public IMsProjectStandardRepository MsProjectStandardRepository { get; set; }
        public IMsProjectRepository MsProjectRepository { get; set; }
        public IMsProjectStandardMeasureItemRepository MsProjectStandardMeasureItemRepository { get; set; }
        public IMsProjectStandardMeasureItemValueRepository MsProjectStandardMeasureItemValueRepository { get; set; }
        public IMsPointTypeRepository MsPointTypeRepository { get; set; }
        public IMsPointTypeMeasureItemRepository MsPointTypeMeasureItemRepository { get; set; }
        public IMsProjectEditLogRepository MsProjectEditLogRepository { get; set; }
        public IStringLocalizer<ServiceResource> Localizer { get; set; }

        public async Task Update()
        {
            var entity1 = MsProjectStandardRepository.GetById("0dfe9175-0e7b-4288-9eec-0589a3fbd585".ToGuid());
            entity1.Content = Dict.S001.ToJsonStr();
            MsProjectStandardRepository.Update(entity1, w => w.Content);

            var entity2 = MsProjectStandardRepository.GetById("604ea8aa-a666-4275-80f7-cd1e6ec0e9de".ToGuid());
            entity2.Content = Dict.S002.ToJsonStr();
            MsProjectStandardRepository.Update(entity2, w => w.Content);

            var entity3 = MsProjectStandardRepository.GetById("e47f7e43-47a7-4eb1-8a41-f6d48e775e72".ToGuid());
            entity3.Content = Dict.S003.ToJsonStr();
            MsProjectStandardRepository.Update(entity3, w => w.Content);

            await UnitOfWork.SaveChangesAsync();
        }

        public async Task Update(StandardListModel standard)
        {
            var entity1 = MsProjectStandardRepository.GetById(standard.MsProjectStandardId.ToGuid());
            if (entity1 == null)
            {
                Logger.Info($"{Localizer["YB0473"].Value}, 标准库Id {standard.MsProjectStandardId}");
                throw new OperationException(Localizer["YB0473"].Value);
            }

            #region 标准库数据

            List<MsProjectStandardMeasureItem> measureItem = new List<MsProjectStandardMeasureItem>();
            List<MsProjectStandardMeasureItemValue> measureItemValue = new List<MsProjectStandardMeasureItemValue>();
            if (standard.Classes == null || standard.Classes.Count == 0)
            {
                throw new OperationException(string.Format(Localizer["YB0162"].Value, standard.Title));
            }

            List<MsPointTypeMeasureItem> msPointTypeMeasureItems = new List<MsPointTypeMeasureItem>();
            // 根据阶段取标准库测量项
            var standardMeasureItem = await MsProjectStandardMeasureItemRepository.GetList(
                new MsProjectStandardMeasureItemCondition { ProjectStandardId = standard.ProjectStandardId, ProjectGuid = standard.ProjectGuid });
            Dictionary<Guid, Guid> keyDict = new Dictionary<Guid, Guid>();   // 标准测量项新旧Guid对照
            List<MsProjectEditLog> addEditLogs = new List<MsProjectEditLog>();
            MsProject project = MsProjectRepository.GetById(standard.ProjectGuid);
            List<MsProjectEditLog> existEditLogs = MsProjectEditLogRepository.Where(x => x.IsPublished == false && x.ProjectId == standard.ProjectGuid).ToList();
            List<StandardClass> oldStandardClassList = JsonConvert.DeserializeObject<List<StandardClass>>(entity1.Content);
            var standardClass = oldStandardClassList.Where(x => x.ClassName == standard.Classes[0].ClassName).FirstOrDefault();
            //先添加删除测量项的日志
            var removeList = standardClass.Items.Where(x => !standard.Classes[0].Items.Select(y => y.Title).Contains(x.Title)).ToList();
            removeList?.ForEach(r =>
            {
                addEditLogs.Add(new MsProjectEditLog
                {
                    EditLogId = Guid.NewGuid(),
                    CreatedBy = OperatorProvider.Get().Id,
                    CreatedDate = DateTime.Now,
                    EditType = MsProjectEditTypeEnum.标准库.ToString(),
                    ProjectId = standard.ProjectGuid,
                    ProjectName = project?.Name,
                    IsDeleted = false,
                    IsPublished = true,
                    ChangeLog = string.Format(Localizer["YB0163"].Value, standard.Classes[0].ClassName, r.Title)
                });
            });
            foreach (var item in standard.Classes[0].Items)
            {
                #region 记录修改日志

                var oldItem = standardClass.Items.Where(x => x.Title == item.Title).FirstOrDefault();
                if (oldItem != null && oldItem.Value.ToString() != item.Value.ToString())
                {
                    string target = standard.Classes[0].ClassName + item.Title;
                    var editLog = existEditLogs.FirstOrDefault(x => x.Target == target);
                    if (editLog == null)
                    {
                        addEditLogs.Add(new MsProjectEditLog
                        {
                            EditLogId = Guid.NewGuid(),
                            CreatedBy = OperatorProvider.Get().Id,
                            CreatedDate = DateTime.Now,
                            EditType = MsProjectEditTypeEnum.标准库.ToString(),
                            ProjectId = standard.ProjectGuid,
                            ProjectName = project?.Name,
                            Target = target,
                            IsDeleted = false,
                            IsPublished = true,
                            ChangeLog = string.Format(Localizer["YB0164"].Value, standard.Classes[0].ClassName, item.Title, item.Value)
                        });
                    }
                    else
                    {
                        editLog.ChangeLog = string.Format(Localizer["YB0163"].Value, item.Title, item.Value);
                        editLog.LastUpdatedBy = OperatorProvider.Get().Id;
                        editLog.LastUpdatedDate = DateTime.Now;
                        MsProjectEditLogRepository.Update(editLog, x => new { x.ChangeLog, x.LastUpdatedBy, x.LastUpdatedDate });
                    }
                }
                else if (oldItem == null)
                {
                    // 没有就是增加
                    addEditLogs.Add(new MsProjectEditLog
                    {
                        EditLogId = Guid.NewGuid(),
                        CreatedBy = OperatorProvider.Get().Id,
                        CreatedDate = DateTime.Now,
                        EditType = MsProjectEditTypeEnum.标准库.ToString(),
                        ProjectId = standard.ProjectGuid,
                        ProjectName = project?.Name,
                        IsDeleted = false,
                        IsPublished = true,
                        ChangeLog = string.Format(Localizer["YB0165"].Value, standard.Classes[0].ClassName, item.Title, item.Value)
                    });
                }

                #endregion 记录修改日志

                // 根据工艺和标准
                var mi = standardMeasureItem.Find(x => x.Code == item.Code
                && x.SupportCraft == item.SupportCraft
                && x.SupportStandard == item.SupportStandard);

                var id = Guid.NewGuid();
                if (mi != null && mi.Id != Guid.Empty)
                {
                    keyDict.Add(id, mi.Id);
                }
                var model = item.CopyTo<MsProjectStandardMeasureItem>();
                model.Id = id;
                model.ProjectStandardId = standard.ProjectStandardId;
                model.ProjectGuid = standard.ProjectGuid;
                model.CompanyGuid = standard.CompanyGuid;
                model.MsProjectStandardMeasureItemId = Guid.NewGuid();
                measureItem.Add(model);

                if (item.Value != null)
                {
                    // 测量项的偏差值
                    var textReader = new JsonTextReader(new StringReader(item.Value.ToString()));
                    JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
                    textReader.Close();
                    var value = new MsProjectStandardMeasureItemValue()
                    {
                        Id = model.Id,
                        SeqNo = 10,
                        Title = string.Empty,
                        Key = "Value",
                        LeftValue = (decimal)jsonArray[0],
                        RightValue = (decimal)jsonArray[1],
                        Unit = item.Unit,
                        ProjectStandardId = standard.ProjectStandardId,
                        CompanyGuid = standard.CompanyGuid,
                        ProjectGuid = standard.ProjectGuid,
                        MsProjectStandardMeasureItemValueId = Guid.NewGuid()
                    };
                    measureItemValue.Add(value);
                }

                if (item.WValue != null)
                {
                    // 测量项的偏差值
                    var textReader = new JsonTextReader(new StringReader(item.Value.ToString()));
                    JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
                    textReader.Close();
                    var value = new MsProjectStandardMeasureItemValue()
                    {
                        Id = model.Id,
                        SeqNo = 20,
                        Title = string.Empty,
                        Key = "WValue",
                        LeftValue = (decimal)jsonArray[0],
                        RightValue = (decimal)jsonArray[1],
                        Unit = item.Unit,
                        ProjectStandardId = standard.ProjectStandardId,
                        CompanyGuid = standard.CompanyGuid,
                        ProjectGuid = standard.ProjectGuid,
                        MsProjectStandardMeasureItemValueId = Guid.NewGuid()
                    };
                    measureItemValue.Add(value);
                }

                if (item.DValue != null)
                {
                    // 测量项的偏差值
                    var textReader = new JsonTextReader(new StringReader(item.Value.ToString()));
                    JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
                    textReader.Close();
                    var value = new MsProjectStandardMeasureItemValue()
                    {
                        Id = model.Id,
                        SeqNo = 30,
                        Title = string.Empty,
                        Key = "DValue",
                        LeftValue = (decimal)jsonArray[0],
                        RightValue = (decimal)jsonArray[1],
                        Unit = item.Unit,
                        ProjectStandardId = standard.ProjectStandardId,
                        CompanyGuid = standard.CompanyGuid,
                        ProjectGuid = standard.ProjectGuid,
                        MsProjectStandardMeasureItemValueId = Guid.NewGuid()
                    };
                    measureItemValue.Add(value);
                }
            }
            MsProjectStandardMeasureItemRepository.RemoveRange(standardMeasureItem, true);  // 删除标准库测量项
            MsProjectStandardMeasureItemRepository.AddRange(measureItem);                   // 新增标准库测量项

            var measureItemValues = await MsProjectStandardMeasureItemValueRepository.GetList(standard.ProjectStandardId, standard.ProjectGuid);
            if (measureItemValues != null && measureItemValues.Count > 0)
            {
                MsProjectStandardMeasureItemValueRepository.RemoveRange(measureItemValues);  // 删除标准库测量项偏差值
            }
            MsProjectStandardMeasureItemValueRepository.AddRange(measureItemValue);          // 新增标准库测量项偏差值

            #endregion 标准库数据

            #region 站点类型测量项

            var pointTypes = await MsPointTypeRepository.GetListByProjectId(standard.ProjectGuid); // 取所有预设站点类型
            if (pointTypes == null || pointTypes.Count == 0)
            {
                throw new OperationException(Localizer["YB0166"].Value);
            }

            // 根据阶段获取站点测量项
            var pointMeasureItems = await MsPointTypeMeasureItemRepository.GetList(
                new MsPointTypeMeasureItemCondition { ProjectStandardId = standard.ProjectStandardId, ProjectGuid = standard.ProjectGuid });
            var newPointMeasureItems = new List<MsPointTypeMeasureItem>();
            foreach (var type in pointTypes)
            {
                foreach (var item in measureItem)
                {
                    bool isCheck = true;
                    if (keyDict.Keys.Contains(item.Id))
                    {
                        var mi = pointMeasureItems.Where(x => x.Id == keyDict[item.Id] && x.MsPointTypeId == type.Id).FirstOrDefault();
                        if (mi != null)
                        {
                            isCheck = mi.IsChecked;
                        }
                    }

                    newPointMeasureItems.Add(new MsPointTypeMeasureItem
                    {
                        Id = item.Id,
                        MsPointTypeId = type.Id,                        // 站点类型Id
                        ProjectStandardId = standard.ProjectStandardId, // 工艺阶段Id
                        IsChecked = isCheck,                            // 测量项是否已选，默认已选中
                        CompanyGuid = standard.CompanyGuid,
                        ProjectGuid = standard.ProjectGuid,
                        MsPointTypeMeasureItemId = Guid.NewGuid()
                    });
                }
            }

            MsPointTypeMeasureItemRepository.RemoveRange(pointMeasureItems);     // 删除站点测量项
            MsPointTypeMeasureItemRepository.AddRange(newPointMeasureItems);     // 新增站点测量项

            #endregion 站点类型测量项

            entity1.Content = standard.Classes.ToJsonStr();
            MsProjectStandardRepository.Update(entity1, w => w.Content);
            DataStore.RefreshProjectStandardData();
            MsProjectRepository.UpdateProjectVersion(standard.ProjectGuid);

            if (addEditLogs.Count > 0)
                MsProjectEditLogRepository.AddRange(addEditLogs);
            await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 获取项目标准库的模板数据
        /// </summary>
        /// <returns></returns>
        public List<MsProjectStandard> GetProjectStandardModelTemplateList()
        {
            var list = MsProjectStandardRepository.Where(w => w.ProjectGuid == new Guid() && w.CompanyGuid == new Guid());
            return list.ToList();
        }

        public List<StandardListModel> GetListByProject(Guid projectGuid)
        {
            var list = MsProjectStandardRepository.Where(w => w.ProjectGuid == projectGuid);
            var standardLists = list.Select(w => new StandardListModel()
            {
                Code = w.Code,
                ProjectStandardId = w.ProjectStandardId,
                Stage = w.Stage,
                Title = w.Title,
                Classes = w.Content.ToObject<List<StandardClass>>(),
                Templates = w.Template.ToObject<List<StandardClass>>(),
                CompanyGuid = w.CompanyGuid,
                ProjectGuid = w.ProjectGuid,
                MsProjectStandardId = w.MsProjectStandardId
            }).OrderBy(x => x.Code).ToList();
            return standardLists;
        }

        public List<StandardListModel> GetList()
        {
            return DataStore.GetStandards(Guid.NewGuid());
        }

        /// <summary>
        /// projectID
        /// </summary>
        /// <returns></returns>
        public List<StandardListModel> GetList(Guid projectID)
        {
            var beforeDt_Sec = System.DateTime.Now;
            var datas = MsProjectStandardRepository.Where(w => w.ProjectStandardId == projectID);
            var afterDT_Sec = System.DateTime.Now;
            var ts_sec = afterDT_Sec.Subtract(beforeDt_Sec);
            Logger.Info($"获取标准值MsProjectStandardRepository.Where{ts_sec.TotalSeconds}s.");

            beforeDt_Sec = System.DateTime.Now;
            var result = datas.Select(w => new StandardListModel()
            {
                Code = w.Code,
                ProjectStandardId = w.ProjectStandardId,
                Stage = w.Stage,
                Title = w.Title,
                Classes = w.Content.ToObject<List<StandardClass>>()
            }).ToList();
            afterDT_Sec = System.DateTime.Now;
            ts_sec = afterDT_Sec.Subtract(beforeDt_Sec);
            Logger.Info($"获取标准值datas.Select花费{ts_sec.TotalSeconds}s.");
            return result;
        }

        public async Task<StandardListModel> GetStageStandard(StageStandardQueryDto obj)
        {
            //项目信息
            var project = await MsProjectRepository.GetByIdAsync(obj.ProjectId);
            var details = project.Details.ToObject<List<Detail>>();
            var detail = details.SingleOrDefault(w => w.Building == obj.BuildingBlock);
            if (detail == null)
                throw new OperationException(Localizer["YB0167"].Value);

            //标准库
            var data = MsProjectStandardRepository.Where(i => i.ProjectGuid == obj.ProjectId && i.ProjectStandardId == obj.StandardId).FirstOrDefault();
            var result = data.CopyTo<StandardListModel>();
            result.Classes = data.Content.ToObject<List<StandardClass>>();

            foreach (var classEntity in result.Classes)
            {
                classEntity.Items = classEntity.Items
                   .Where(w =>
                       string.IsNullOrEmpty(w.SupportStandard) || w.SupportStandard.Equals(detail.Standard)
                       ).Where(w => w.Type == obj.Type).ToList();
            }
            return result;
        }

        /// <summary>
        /// 根据条件获取标准库信息
        /// </summary>
        /// <param name="condition">查询条件</param>
        /// <returns></returns>
        public async Task<List<StandardListModel>> GetListCondition(StandardCondition condition)
        {
            var datas = await MsProjectStandardRepository.WhereAsync(x => x.ProjectStandardId == condition.ProjectStandardId);
            return datas.Select(w => new StandardListModel()
            {
                Code = w.Code,
                ProjectStandardId = w.ProjectStandardId,
                Stage = w.Stage,
                Title = w.Title,
                Classes = w.Content.ToObject<List<StandardClass>>(),
                Templates = w.Template.ToObject<List<StandardClass>>()
            }).OrderBy(x => x.Code).ToList();
        }

        public async Task<List<MsPointTypeDto>> GetPointTypeDetails(Guid projectStandardId, Guid houseMapId, Guid ProjectGuid)
        {
            return await MsPointTypeRepository.GePointTypeDetail(projectStandardId, houseMapId, ProjectGuid);
        }

        /// <summary>
        /// 保存站点类型测量项
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public async Task Update(List<MsPointTypeDto> models)
        {
            var msPointTypeMeasureItems = new List<MsPointTypeMeasureItem>();

            if (models != null && models.Count > 0)
            {
                foreach (var item in models)
                {
                    var oldList = await MsPointTypeMeasureItemRepository.GetListAsNoTracking(x => x.MsPointTypeId == item.Id
                    && x.ProjectGuid == item.ProjectGuid);
                    foreach (var mi in item.MeasureItem)
                    {
                        var old = oldList.FirstOrDefault(x => x.MsPointTypeMeasureItemId == mi.MsPointTypeMeasureItemId);
                        if (old != null && old.IsChecked != mi.IsChecked)
                        {
                            MsProjectEditLogRepository.Add(new MsProjectEditLog
                            {
                                ProjectId = mi.ProjectGuid,
                                ProjectName = "",
                                CreatedBy = OperatorProvider.Get().YunUserGuid,
                                CreatedDate = DateTime.Now,
                                EditLogId = Guid.NewGuid(),
                                EditType = MsProjectEditTypeEnum.标准库.ToString(),
                                IsDeleted = false,
                                IsPublished = true,
                                ChangeLog = string.Format(Localizer["YB0168"].Value, item.Name, mi.Title)
                            });
                        }
                        var model = new MsPointTypeMeasureItem()
                        {
                            Id = mi.MeasureItemId,
                            IsChecked = mi.IsChecked,
                            MsPointTypeId = item.Id,
                            ProjectStandardId = mi.ProjectStandardId,
                            CompanyGuid = mi.CompanyGuid,
                            ProjectGuid = mi.ProjectGuid,
                            MsPointTypeMeasureItemId = mi.MsPointTypeMeasureItemId
                        };
                        MsPointTypeMeasureItemRepository.Update(model);
                    }
                }
                MsProjectRepository.UpdateProjectVersion(models[0].ProjectGuid);
                await UnitOfWork.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 从基础标准库同步项目的标准库
        /// </summary>
        public async Task<UpdateResultDto> UpdateFromBase(Guid projectId)
        {
            var res = new UpdateResultDto();
            Guid baseProjectId = Guid.Empty;
            var projectIds = new List<Guid> { baseProjectId, projectId };
            var projectStandardQuery = MsProjectStandardRepository.GetAll().Where(x => projectIds.Contains(x.ProjectGuid)).AsNoTracking();
            var projectStandardVersions = await projectStandardQuery.Select(x => new { x.ProjectGuid, x.ProjectStandardId, x.Version }).ToListAsync();

            var needUpdateStandardIds = projectStandardVersions.Where(x => x.ProjectGuid == projectId && x.Version < projectStandardVersions.Find(y => y.ProjectGuid == baseProjectId && y.ProjectStandardId == x.ProjectStandardId).Version).Select(x => x.ProjectStandardId);

            var pointTypes = await MsPointTypeRepository.GetAll().Where(x => !x.IsDeleted && projectIds.Contains(x.ProjectGuid)).AsNoTracking().Select(x => new { x.Id, x.ProjectGuid }).ToListAsync();
            var projectpointTypeIds = pointTypes.Where(x => x.ProjectGuid == projectId).Select(x => x.Id);
            var needAddpointTypeIds = pointTypes.Where(x => x.ProjectGuid == baseProjectId && !projectpointTypeIds.Contains(x.Id)).Select(x => x.Id);

            if ((needUpdateStandardIds == null || needUpdateStandardIds.Count() < 1) && (needAddpointTypeIds == null || needAddpointTypeIds.Count() < 1))
            {
                res.IsUpdated = false;
                res.Message = "当前标准库已经是最新无需更新";
            }
            else
            {
                await MsProjectStandardRepository.SyncProjectStandard(projectId, OperatorProvider.Get().YunUserGuid);
                res.IsUpdated = true;
                res.Message = "标准库已更新完成";
            }
            
            return res;
        }
    }
}